﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Net.NetworkInformation;
using System.Windows.Forms;

namespace NaSha
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        private static Bitmap LoadImage()
        {
            // Создаем диалог открытия файла
            var openFileDialog = new OpenFileDialog
            {
                Filter = @"JPEG Image Files (.jpg)|*.jpg",
                FilterIndex = 1,
                Multiselect = false
            };

            // Если пользователь нажал ок
            var result = openFileDialog.ShowDialog();
            if (result != DialogResult.OK) return null; 
                
            // Создаем поток и битмап из него
            var fileStream = openFileDialog.OpenFile();
            var image = new Bitmap(fileStream);
            fileStream.Close();

            return image;
        }

        private static void SaveImage(PictureBox box)
        {
            var saveDialog = new SaveFileDialog
            {
                Filter = @"JPEG Image Files (.jpg)|*.jpg",
                FilterIndex = 1
            };

            var result = saveDialog.ShowDialog();
            if (result != DialogResult.OK) return;

            var image = new Bitmap(box.Image);
            image.Save(saveDialog.FileName, ImageFormat.Jpeg);    
        }

        private void loadMainImage_Click(object sender, EventArgs e)
        {
            var image = LoadImage();

            if (image == null) return;

            // Преобразовываем каждый пиксель битмапа в черно-белый цвет (без оттенков серого)
            for (var i = 0; i < image.Width; i++)
            {
                for (var j = 0; j < image.Height; j++)
                {
                    var pixel = image.GetPixel(i, j);
                    image.SetPixel(i, j, pixel.GetBrightness() > 0.7 ? Color.White : Color.Black);
                }
            }
            
            // Отображаем превью изображения
            // Разрешаем сохранять и кодировать
            mainImageBox.Image = image;
            saveMainImage.Enabled = true;
            codeMainImage.Enabled = true;
        }

        private void loadShadow1_Click(object sender, EventArgs e)
        {
            var image = LoadImage();
            if (image == null) return;
            shadow1Box.Image = image;
        }

        private void loadShadow2_Click(object sender, EventArgs e)
        {
            var image = LoadImage();
            if (image == null) return;
            shadow2Box.Image = image;
        }

        private void saveMainImage_Click(object sender, EventArgs e)
        {
            SaveImage(mainImageBox);
        }

        private void saveShadow1_Click(object sender, EventArgs e)
        {
            if (shadow1Box.Image == null) return;
            SaveImage(shadow1Box);
        }

        private void saveShadow2_Click(object sender, EventArgs e)
        {
            if (shadow2Box.Image == null) return;
            SaveImage(shadow2Box);
        }

        private readonly Random _random = new Random();

        private void CodeBlackPixel(Bitmap shadow1, Bitmap shadow2, int i, int j)
        {
            var style = _random.Next(5);
            switch (style)
            {
                case 0:
                    shadow1.SetPixel(2*i, 2*j, Color.Black);
                    shadow1.SetPixel(2*i+1, 2*j, Color.Black);
                    shadow1.SetPixel(2*i, 2*j+1, Color.White);
                    shadow1.SetPixel(2*i+1, 2*j+1, Color.White);

                    shadow2.SetPixel(2*i, 2*j, Color.Black);
                    shadow2.SetPixel(2*i+1, 2*j, Color.Black);
                    shadow2.SetPixel(2*i, 2*j+1, Color.White);
                    shadow2.SetPixel(2*i+1, 2*j+1, Color.White);
                    break;
                case 1:
                    shadow1.SetPixel(2*i, 2*j, Color.White);
                    shadow1.SetPixel(2*i+1, 2*j, Color.White);
                    shadow1.SetPixel(2*i, 2*j+1, Color.Black);
                    shadow1.SetPixel(2*i+1, 2*j+1, Color.Black);

                    shadow2.SetPixel(2*i, 2*j, Color.White);
                    shadow2.SetPixel(2*i+1, 2*j, Color.White);
                    shadow2.SetPixel(2*i, 2*j+1, Color.Black);
                    shadow2.SetPixel(2*i+1, 2*j+1, Color.Black);
                    break;
                case 2:
                    shadow1.SetPixel(2*i, 2*j, Color.White);
                    shadow1.SetPixel(2*i+1, 2*j, Color.Black);
                    shadow1.SetPixel(2*i, 2*j+1, Color.Black);
                    shadow1.SetPixel(2*i+1, 2*j+1, Color.White);

                    shadow2.SetPixel(2*i, 2*j, Color.White);
                    shadow2.SetPixel(2*i+1, 2*j, Color.Black);
                    shadow2.SetPixel(2*i, 2*j+1, Color.Black);
                    shadow2.SetPixel(2*i+1, 2*j+1, Color.White);
                    break;
                case 3:
                    shadow1.SetPixel(2*i, 2*j, Color.Black);
                    shadow1.SetPixel(2*i+1, 2*j, Color.White);
                    shadow1.SetPixel(2*i, 2*j+1, Color.White);
                    shadow1.SetPixel(2*i+1, 2*j+1, Color.Black);

                    shadow2.SetPixel(2*i, 2*j, Color.Black);
                    shadow2.SetPixel(2*i+1, 2*j, Color.White);
                    shadow2.SetPixel(2*i, 2*j+1, Color.White);
                    shadow2.SetPixel(2*i+1, 2*j+1, Color.Black);
                    break;
                case 4:
                    shadow1.SetPixel(2 * i, 2 * j, Color.Black);
                    shadow1.SetPixel(2 * i + 1, 2 * j, Color.White);
                    shadow1.SetPixel(2 * i, 2 * j + 1, Color.Black);
                    shadow1.SetPixel(2 * i + 1, 2 * j + 1, Color.White);

                    shadow2.SetPixel(2 * i, 2 * j, Color.Black);
                    shadow2.SetPixel(2 * i + 1, 2 * j, Color.White);
                    shadow2.SetPixel(2 * i, 2 * j + 1, Color.Black);
                    shadow2.SetPixel(2 * i + 1, 2 * j + 1, Color.White);
                    break;
                case 5:
                    shadow1.SetPixel(2 * i, 2 * j, Color.White);
                    shadow1.SetPixel(2 * i + 1, 2 * j, Color.Black);
                    shadow1.SetPixel(2 * i, 2 * j + 1, Color.White);
                    shadow1.SetPixel(2 * i + 1, 2 * j + 1, Color.Black);

                    shadow2.SetPixel(2 * i, 2 * j, Color.White);
                    shadow2.SetPixel(2 * i + 1, 2 * j, Color.Black);
                    shadow2.SetPixel(2 * i, 2 * j + 1, Color.White);
                    shadow2.SetPixel(2 * i + 1, 2 * j + 1, Color.Black);
                    break;
            }
        }

        private void CodeWhitePixel(Bitmap shadow1, Bitmap shadow2, int i, int j)
        {
            var style = _random.Next(5);
            switch (style)
            {
                case 0:
                    shadow1.SetPixel(2 * i, 2 * j, Color.Black);
                    shadow1.SetPixel(2 * i + 1, 2 * j, Color.Black);
                    shadow1.SetPixel(2 * i, 2 * j + 1, Color.White);
                    shadow1.SetPixel(2 * i + 1, 2 * j + 1, Color.White);

                    shadow2.SetPixel(2 * i, 2 * j, Color.White);
                    shadow2.SetPixel(2 * i + 1, 2 * j, Color.White);
                    shadow2.SetPixel(2 * i, 2 * j + 1, Color.Black);
                    shadow2.SetPixel(2 * i + 1, 2 * j + 1, Color.Black);
                    break;
                case 1:
                    shadow1.SetPixel(2 * i, 2 * j, Color.White);
                    shadow1.SetPixel(2 * i + 1, 2 * j, Color.White);
                    shadow1.SetPixel(2 * i, 2 * j + 1, Color.Black);
                    shadow1.SetPixel(2 * i + 1, 2 * j + 1, Color.Black);

                    shadow2.SetPixel(2 * i, 2 * j, Color.Black);
                    shadow2.SetPixel(2 * i + 1, 2 * j, Color.Black);
                    shadow2.SetPixel(2 * i, 2 * j + 1, Color.White);
                    shadow2.SetPixel(2 * i + 1, 2 * j + 1, Color.White);
                    break;
                case 2:
                    shadow1.SetPixel(2 * i, 2 * j, Color.White);
                    shadow1.SetPixel(2 * i + 1, 2 * j, Color.Black);
                    shadow1.SetPixel(2 * i, 2 * j + 1, Color.Black);
                    shadow1.SetPixel(2 * i + 1, 2 * j + 1, Color.White);

                    shadow2.SetPixel(2 * i, 2 * j, Color.Black);
                    shadow2.SetPixel(2 * i + 1, 2 * j, Color.White);
                    shadow2.SetPixel(2 * i, 2 * j + 1, Color.White);
                    shadow2.SetPixel(2 * i + 1, 2 * j + 1, Color.Black);
                    break;
                case 3:
                    shadow1.SetPixel(2 * i, 2 * j, Color.Black);
                    shadow1.SetPixel(2 * i + 1, 2 * j, Color.White);
                    shadow1.SetPixel(2 * i, 2 * j + 1, Color.White);
                    shadow1.SetPixel(2 * i + 1, 2 * j + 1, Color.Black);

                    shadow2.SetPixel(2 * i, 2 * j, Color.White);
                    shadow2.SetPixel(2 * i + 1, 2 * j, Color.Black);
                    shadow2.SetPixel(2 * i, 2 * j + 1, Color.Black);
                    shadow2.SetPixel(2 * i + 1, 2 * j + 1, Color.White);
                    break;
                case 4:
                    shadow1.SetPixel(2 * i, 2 * j, Color.Black);
                    shadow1.SetPixel(2 * i + 1, 2 * j, Color.White);
                    shadow1.SetPixel(2 * i, 2 * j + 1, Color.Black);
                    shadow1.SetPixel(2 * i + 1, 2 * j + 1, Color.White);

                    shadow2.SetPixel(2 * i, 2 * j, Color.White);
                    shadow2.SetPixel(2 * i + 1, 2 * j, Color.Black);
                    shadow2.SetPixel(2 * i, 2 * j + 1, Color.White);
                    shadow2.SetPixel(2 * i + 1, 2 * j + 1, Color.Black);
                    break;
                case 5:
                    shadow1.SetPixel(2 * i, 2 * j, Color.White);
                    shadow1.SetPixel(2 * i + 1, 2 * j, Color.Black);
                    shadow1.SetPixel(2 * i, 2 * j + 1, Color.White);
                    shadow1.SetPixel(2 * i + 1, 2 * j + 1, Color.Black);

                    shadow2.SetPixel(2 * i, 2 * j, Color.Black);
                    shadow2.SetPixel(2 * i + 1, 2 * j, Color.White);
                    shadow2.SetPixel(2 * i, 2 * j + 1, Color.Black);
                    shadow2.SetPixel(2 * i + 1, 2 * j + 1, Color.White);
                    break;
            }
        }

        private void codeMainImage_Click(object sender, EventArgs e)
        {
            var original = new Bitmap(mainImageBox.Image);

            var shadow1 = new Bitmap(original.Width * 2, original.Height * 2);
            var shadow2 = new Bitmap(original.Width * 2, original.Height * 2);

            for (var i = 0; i < original.Width; i++)
            {
                for (var j = 0; j < original.Height; j++)
                {
                    if (original.GetPixel(i, j).GetBrightness() < 0.5)
                    {
                        CodeBlackPixel(shadow1, shadow2, i, j);    
                    }
                    else
                    {
                        CodeWhitePixel(shadow1, shadow2, i, j); 
                    }
                }
            }

            shadow1Box.Image = shadow1;
            shadow2Box.Image = shadow2;
        }

        private void assembleShadows_Click(object sender, EventArgs e)
        {
            if (shadow1Box.Image == null || shadow2Box.Image == null) return;

            if ((shadow1Box.Image.Width != shadow2Box.Image.Width) ||
                shadow1Box.Image.Height != shadow2Box.Image.Height) return;

            var shadow1 = new Bitmap(shadow1Box.Image);
            var shadow2 = new Bitmap(shadow2Box.Image);

            var assembledImage = new Bitmap(shadow1.Width/2, shadow1.Height/2);

            var assembled1 = 0;
            for (var i = 0; i < shadow1.Width; i+=2)
            {
                var assembled2 = 0;
                for (var j = 0; j < shadow1.Height; j+=2)
                {
                    var pixel1 = false;
                    var pixel2 = false;
                    if (shadow1.GetPixel(i, j).GetBrightness() < 0.5) pixel1 = true;
                    if (shadow2.GetPixel(i, j).GetBrightness() < 0.5) pixel2 = true;
                    // XOR пикселей левого верхнего угла каждого квадранта 2х2 изображения
                    assembledImage.SetPixel(assembled1, assembled2, (pixel1 ^ pixel2) ? Color.White : Color.Black);
                    assembled2++;
                }
                assembled1++;
            }

            mainImageBox.Image = assembledImage;

            codeMainImage.Enabled = true;
            saveMainImage.Enabled = true;
        }

        private void clearAll_Click(object sender, EventArgs e)
        {
            mainImageBox.Image = null;
            shadow1Box.Image = null;
            shadow2Box.Image = null;
            codeMainImage.Enabled = false;
            saveMainImage.Enabled = false;
        }
    }
}
